Xbasic

Object Events

Description

Many events are triggered by objects, such as buttons, fields, and forms. The object events are generally triggered in response to the cursors movements into and out of the object (i.e., the changing of focus from one place to another).

Events for Button Objects

A button object can have scripts attached to the following events:

  • OnPush

    The button is pressed. Use to run a script.

  • OnArrive

    The button gets focus.

  • OnDepart

    The button looses focus.

  • CanArrive

    Just before the button gets focus.

  • CanDepart

    Just before the button looses focus.

  • OnFlyover

    When the mouse is over the object. Use to change the field's colors or display a message.

  • OnFlyoverLeave

    When the mouse pointer is no longer over the object.

Scripts are generally attached to a buttons OnPush event. The following sequence of events were generated when an operator moved the cursor to a button, clicked it, and moved the cursor off the button.

Sequence of Events for Buttons

Event Name
Type
1. OnFlyover

Control type.

2. CanArrive

Control type.

3. CanDepart

Control type.

4. OnDepart

Control type.

5. OnArrive

Control type.

6. OnPush

Control type.

7. onactivate

Form type.

8. OnFlyoverLeave

Control type.

Events for Type-In Objects

The following events are triggered by all forms of the type-in object: Type-In, List boxes, Drop-Down lists, Radio buttons, Check boxes, Two-state, and Multi-state buttons:

  • change>onchange

    The contents of the field object are changed. Use to detect when the field has been changed.

  • OnArrive

    The field gets focus.

  • OnDepart

    The field looses focus.

  • CanArrive

    Just before the field gets focus.

  • CanDepart

    Just before the field looses focus.

  • OnFlyover

    When the mouse is over the object. Use to change the field's colors or display a message.

  • OnFlyoverLeave

    When the mouse pointer is no longer over the object.

For type-in fields, the onchange event fires when the control looses focus. For radio button, two-state button, multi-state button, and list box fields, the onchange event fires as soon as the fields value changes.For example, assume that you have a form with an Account_Number field. If the user makes a change to the value in this field, you want to be sure that this change was made intentionally, and not by mistake. If the user confirms that the change was intentional, the changed value is retained. Otherwise, the initial value is restored. To do this, scripts must be attached to the fields OnArrive and onchange events. A flag variable is used to prevent the onchange script from playing back a second time when the initial value is restored.The following script is attached to the Account_Number fields OnArrive event:

dim flag as L
dim SHARED init_valueAS C
'Set a variable to the initial value in account_number init_value= account_number.value
'Set the flag variable to .T.
flag = .T.

The script for the onchange event is:

if flag then
    code = ui_msg_box("Warning", "You have changed the value in
    this field. Are you sure you want to change the
    value? ", UI_OK_SELECTED + UI_QUESTION_SYMBOL)
    if (code = 2) then 'User selected Cancel button
      this.value = init_value
        this.refresh()
        flag = .F.
    end if
end if

The following example shows how the forms tab order can be dynamically controlled. In this example, the script is attached to the OnDepart event for the Same_shipping field:

If same_shipping.value = .T. then
    Ship_via.activate()
Else
    Ship_Address.activate()
End if

The following sequence of events were generated when an operator placed the cursor in a type-in field, changed its contents, and moved the cursor to a different field.

Sequence of Events for Type-In Fields

Event Name
Type
1. OnFlyover

Control

2. CanArrive

Control

3. CanEditField

Field

4. OnEditField

Field

5. OnArrive

Control

6. CanDepart

Control

7. CanWriteField

Field

8. onchange

Control

9. OnDepart

Control

10. OnWroteField

Field

11. OnFlyoverLeave

Control

The following sequence of events were generated when an operator placed the cursor on a check box, clicked it, and moved the cursor off it.

Sequence of Events for Check Boxes

Event Name
Type
1. OnFlyover

Control

2. CanEditField

Field

3. CanArrive

Control

4. OnEditField

Field

5. OnArrive

Control

6. CanArrive

Control

7. CanChangeRecord

Table

8. onchangeRecord

Table

9. CanWriteField

Field

10. onchange

Control

11. onactivate

Form

The following sequence of events were generated when an operator moved the cursor to a radio button, selected it, clicked one of the buttons, and moved the cursor off it.

Sequence of Events for Radio Buttons

Event Name
Type
1. OnFlyover

Control

2. CanEditField

Field

3. CanArrive

Control

4. OnEditField

Field

5. OnArrive

Control

6. CanArrive

Control

7. onactivate

Form

8. CanWriteField

Field

9. onchange

Control

10. OnDepart

Control

11. OnWroteField

Field

12. OnFlyoverLeave

Control

Events for Image Reference Fields

The following events are triggered by image reference fields:

Event Name
Occurs When
onchange

When new images are added

OnArrive

The field gets focus.

OnDepart

The field looses focus.

CanArrive

Just before the field gets focus.

CanDepart

Just before the field looses focus.

OnFlyover

When the mouse pointer is over the object.

OnFlyover_leave

When the mouse pointer is no longer over the object.

Events

  • OnExit

    When the browse object is exited. This will occur after the form that encloses the browse object is closed.

  • OnInit

    When the browse object is created. This will occur after the form that encloses the browse object is instantiated.

  • OnFetch

    When the browse is re-synchronized (i.e. when Alpha Anywhere fetches a record). Whenever the user navigates to a new row in the browse, this event and the OnRowChange event will fire. However, the OnFetch event will also fire if the browse is re-synchronized without navigating to a new row.

  • CanRowChange

    Just before you navigate to a new row.

  • OnRowChange

    When you navigate to a new row in the browse.

  • OnRowDblClick

    When you double click on a row selector. If the browse object is read only, then this event will fire if you double click within the row.

  • CanArrive

    Before the browse object on the form gets focus.

  • CanDepart

    Before the browse object on the form can loose focus.

  • CanSave

    Before a record in the browse is saved.

  • OnArrive

    After the browse object on the form has got focus.

  • OnDepart

    After the browse object on the form has lost focus.

  • OnSave

    After a record in the browse is saved.

  • onchange

    Fires when data in a browse column is changed. Events can be defined for each column in the browse. Event handlers for this event are defined by creating specially named functions in the generic 'Events' event. Function name is of the form _onchange. For example, here is how to define an event handler for the 'lastname' column in a browse:

    • 1. Edit the 'Events' event.

    • 2. Define the following function ('this' is an alias that refers to the browse object that contains the browse column):

      function lastname_onchange as v ()
          ui_msg_box("On Change Event for Browse. Browse name is: ",this.name())
      end function
  • TitleClick

    Fires when a browse column is clicked. To enable this event, you must first set the 'Column title click behavior' to 'Click fires user event' (see Browse properties). Event handlers for this event are defined by creating specially named functions in the generic 'Events' event. Function name is of the form _TitleClick. See the 'onchange' event for more information on how to create event handlers.

In the following example, assume you have a table called Customers. You have a form for this table that shows a browse view of your records. When you double click on a row in the browse, a form called Customer_dlg is opened as a dialog allowing you to edit the record.

'Open "customer_dlg" invisibly
frm = :form.load("customer_dlg", "dialog")
'Set a variable to the current record's customer Id value
cust_id = parent:browse1:cust_id.value
'Set the index on the "customer_dlg" form
frm.index_set("cust_id")
'Find the correct record
frm.find(cust_id)
'Show the dialog box this also automatically activates it
frm.show()
'When the user closes the dialog box, the dialog is not really
'closed. It must be closed with the close() method.
frm.close()

In the following example, a script attached to the CanDepart event causes a calculated field in the parent table to update when focus leaves the embedded browse. Consider the sample Invoice application that ships with Alpha Anywhere. Say you wanted to have a summary field in the invoice_header table that summarized the extended totals in the child invoice_items table. Assume that you had a field in the invoice_header table called summary (numeric 12,2), and had defined the following calculated field rule for this field:

dbsum("invoice_items", "invoice_number", INVOICE_NUMBER, "extension")

While this expression is correct, you would find that the field was not displaying the correct value when you entered new line items into the embedded browse. The reason for this is that calculated fields only evaluate when a record is in change or enter mode, and when you are entering line item records, the invoice_header table is in view mode, not change or enter.By putting this script on the embedded forms CanDepart event, you can force the calculated fields in the invoice_header table to recalculate:

parentform.commit()
t = table.current()
t.change_begin()
t.change_end(.T.)
parentform.resynch()

Event Name
Type
1. CanArrive

Control

2. OnArrive

Control

3. CanRowChange

Control

4. OnFetch

Form

5. OnRowChange

Control

6. onactivate

Form

7. CanArrive

Control

8. CanEditField

Field

9. OnEditField

Field

10. CanChangeRecord

Record

11. onchangeRecord

Record

12. OnFetch

Form

13. CanChangeRecord

Record

14. onchangeRecord

Record

15. CanWriteField

Field

16. CanDepart

Control

17. OnDepart

Control

18. OnWroteField

Field

19. CanSaveRecord

Record

20. OnSaveRecord

Record

Events for Forms

The following events are triggered when you display, leave, or work with a form:

  • AskSaveChange

    When the user attempts to close a form before committing changes to a changed record. Allows the programmer to customize the dialog that the user sees when aborting a record. (See AskSaveChange and AskSaveEnter Events below for more details).

  • AskSaveEnter

    When the user attempts to close a form before committing changes to a new record. Allows the programmer to customize the dialog that the user sees when aborting a record. (See AskSaveChange and AskSaveEnter Events below for more details).

  • CanChange

    Before a control on a form is edited. The CanChange event only fires if:

    • A new record has been fetched

    • You are not entering a new record.

    • The restrict_change property is FALSE

    • The CanChange event will not occur after changes to a record had been saved.

  • CanExit

    Before the form is closed. You can prevent the form (and therefore Alpha Anywhere as well) from being closed by including the CANCEL()command in the script attached to this event. This event is not fired when you close the form or browse with the .CLOSE() method unless you set its argument to .F. . Note the following limitation: If you have multiple forms open, each of which has a CanExit event, and you click the X on the main window frame, only the CanExit event of the first window that was opened will fire.

  • CanSave

    Before the record is saved. Note that there is also a CanSaveRecord field rule event. However, if you cancel the CanSaveRecord event, the pending record is lost. If you cancel this event, the record is not saved, but the pending record is preserved, allowing the user to make necessary corrections before trying to save the record again.

  • activate>onactivate

    The form window is activated (given focus).

  • ondeactivate

    The form window is deactivated (focus is sent to another window).

  • OnEnter

    The form is put in Enter mode to enter a new record.

  • OnExit

    The form is closed.

  • OnFetch

    A record is retrieved from the current table or set.

  • OnInit

    The form is opened.

  • OnKey

    Whenever a key is pressed while the form has focus. Variables set:

    • A_USER.KEY.VALUE contains the key (key is same format that is used by SYS_SEND_KEYS() i.e. A is the character A, {F1} is the F1 key.

    • A_USER.KEY.EVENT is either up or down or repeat depending whether the key is being pushed, held down or released.

    • A_USER.KEY.HANDLED is set to .T. if the key was handled by the OnKey event. If you set this variable to .T., then the keystroke is not passed through to Alpha Anywhere (i.e. it is eaten by the OnKey script).

  • For example, the following OnKey script will close Alpha Anywhere when the user presses Alt-X:

    If (A_USER.KEY.VALUE = "{%X}") then
       If (A_USER.KEY.EVENT = "down") then
            :a5.close()
       End if
    End if
  • TIP : To see how Alpha Anywhere represents different key combinations, define the following OnKey script for a form, then open the trace window and try out different key combinations:

    trace.writeln("key: " + A_USER.KEY.VALUE + " event: " + A_USER.KEY.EVENT)
  • See Also: Script Recorder, Closing a Form with the ESC Key, Running a Script with a Function Key

  • OnSave

    The record that is being edited is saved.

  • OnTimer

    The timer interval has elapsed. The timer interval for a form is set by editing the form, selecting Form, Properties and setting a timer interval. For example, if the timer interval is set to 5 seconds, the OnTimer script will execute every five seconds.

The following example is obsolete in V5 because you can now select Modal/Modeless data entry as a property of each Form or Browse layout. The example is nevertheless still interesting since it describes a use for the OnFetch event.

The following example shows how the OnFetch event can be used to turn off Alpha Anywhere's modeless data entry. Modeless data entry allows the user to just start typing a new value in a field without having to explicitly put the record in change or enter mode. In some applications it may be desirable to turn off modeless data entry, thus requiring the user to press a button before the record can be edited.Attach this script to the forms OnFetch event:

this.allow_change(.f.)
While the above example should work in most cases, in some cases, it would be possible to get a Maximum Stack Depth Exceeded error message when scrolling through the records very quickly. This is because the OnFetch event is fired a second time before the current instance has finished executing. The current instance is put onto a stack until it can be completed. The stack has a limited capacity. If enough uncompleted instances of the script are pushed onto the stack, the stack will eventually overflow. This situation can be corrected by preventing a second instance of the script from starting until the first instance is complete. The following code shows how to do this:
dim shared busy as L
if (.not. busy) then
    busy = .T.
    this.allow_change(.f.)
    busy = .f.
end if

When the user wants to edit a record, he presses a button with this script attached to the buttons OnPush event:

parent.allow_change(.T.)

Notice that the script attached to the OnFetch event uses the this alias to refer to the form, while the script attached to the button uses the alias parent to refer to the form. This is because the button is a child of the form, whereas the OnFetch event occurs at the level of the form. (Both scripts could also use parentform to refer to the form).

AskSaveChange and AskSaveEnter Events

The AskSaveChange and AskSaveEnter events fire when the user attempts to close a form before committing changes to a new or edited record. They allow the user to custom design the dialog that Alpha Anywhere displays asking the user to confirm the action.

RESULT_CODE Variable

RESULT_CODE is a system variable that is used in conjunction with the AskSaveChange and AskSaveEnter events. For example, if the result_code variable is set to UI_YES_SELECTED, then the record is saved, and Alpha Anywhere does not present its dialog asking the user for confirmation. If you do not define a script for either the AskSaveChange, or AskSaveEnter event, or do not set the numeric result_code, then the default Alpha Anywhere dialog appears.

Examples

Change the wording on the dialog to something specific to the application:

result_code = ui_msg_box("Warning","Save invoice change in progress", UI_YES_NO_CANCEL)

Change the meaning of Yes from save to abort:

result_code = ui_msg_box("warning","lose change(s)", UI_YES_NO_CANCEL)
if (result_code = UI_YES_SELECTED) then
    result_code = UI_NO_SELECTED
else if result_code = UI_NO_SELECTED
    result_code = UI_YES_SELECTED
end if

Automatically save the record (i.e. do not ask for confirmation)

result_code = UI_YES_SELECTED

Events for Tab Object on Forms

The following events are triggered when the user changes the active page on a tab control on a form:

Event Name
Occurs When
CanTabChange

Before the current tab page loses focus and before the target tab page gets focus.

OnTabChange

After the target tab page gets focus.

You can use the CanTabChange event to prevent the user from moving off the current tab page.For example, you might have created a dialog form with a tab control on it. You want the user to complete filling in all of the controls on each page of the tab control before advancing to the next tab page. You could attach the following code to the tab controls CanTabChange event:

'Get the current tab page.
Page = :customer_dialog:tabbed1.tab_get()
select
    case Page = 1
        if (:customer_dialog:last_name = "") then
          cancel()
            ui_msg_box("Error", "Fill in last name")
        end if
    case Page = 2
        if (:customer_dialog:address = "") then
            cancel()
            ui_msg_box("Error", "Fill in address")
        end if
end select

Events for Reports

The following events are triggered when the user a user does a print or print preview of a report:

Event Name
Occurs When
OnPrintInit

Before the report begins to print and at the beginning of preview.

OnRecord

After each detail record has printed.

OnPrintExit

After the report has finished printing. In the case of print preview, when the user closes the print preview window.

To specify scripts for the OnPrintInit and OnPrintExit events, select Report > Actions. This opens the Script Editor. In the Container drop down box, select the report name. Then select the name of the event you wish to define in the Script drop down box.To specify a script for the OnRecord event, open the script editor as Defined above, select Detail in the Container drop down box.You can use the OnPrintInit event to prompt the user for variables by opening a form as a dialog, or by using a UI_GET_TEXT() function, or by running an Xdialog box. These variables might then be used in the report's filter and order expression (defined in the report's Detail properties). IMPORTANT: The variables that you prompt for in the OnPrintInit event must be DIMmed as "shared" or "global". For example, the following Xdialog box prompts for the state. The report filter then has the filter expression: "state = var->whatstate".

dim shared whatstate as C
Report_vars = ui_dlg_box("What State",<<%dlg%
What state: .50whatstate;
;
%dlg%)
'Check if user clicked the cancel button.
'If so, then cancel the report.
If report_vars = "cancel" then
    Cancel()
End if

You can use the OnRecord event to update records after they have printed. For example, in an invoicing application, you might have a Status field in the invoice_header table. After you print out invoices, you might want to update this field to say Printed. Here is how you could do this:

t = table.current()
t.change_begin()
t.status = "Printed"
t.change_end(.T.)

Events for User Defined Controls

The Form Editor in Alpha Anywhere has a control called User Defined Control that allows an Xbasic programmer to make a custom control.A user puts a User Defined Control (UDC) on a form using the UDC object on the form editors toolbox. You select the tool and draw the object on the form. Once you have defined the UDC on the form, you can then specify the Xbasic code for its various events.A UDC allows the user to write custom controls entirely within Xbasic using the Windows API (or other external libraries) to draw the contents, handle key and mouse events, and react to timer events. See User Defined Controls for more information.The A_USER.HWND variable is used for window control and is always defined.

Events and Associated Variables

See Also